package vg.services.graph_view_manager.realization.graph_view.smart_graph_view.realization;

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.atomic.AtomicBoolean;

import vg.services.graph_view_manager.interfaces.graph_view.IGraphAction;
import vg.services.graph_view_manager.interfaces.graph_view.IGraphRenderer;
import vg.services.graph_view_manager.realization.graph_view.smart_graph_view.interfaces.ISGVTopScreen;
import vg.services.graph_view_manager.realization.graph_view.smart_graph_view.interfaces.ISGVActionManager;
import vg.services.main_manager.MainManager;

public class SGVPatchManager implements ISGVActionManager {
	// Main data
	private ISGVTopScreen topScreen = null;
	
	// Main components 
	private Queue<IGraphAction> actions = null;
	private int currentPatchId = 0;
	private int currentCompletePatchId = -1;

    private AtomicBoolean stop = new AtomicBoolean(false);
	
	// Mutex
	private final Object generalMutex = new Object();
	
	/**
	 * Constructor
	 */
	public SGVPatchManager(ISGVTopScreen topScreen) {
		this.topScreen = topScreen;
		
		actions = new ArrayDeque<IGraphAction>();
		
		initThread();
	}
	
	@Override
	public int addAction(IGraphAction action) {
		synchronized (generalMutex) {
            actions.add(action);
			return currentPatchId++;
		}
	}
	
	@Override
	public boolean isComplete(int patchId) {
		synchronized (generalMutex) {
			return patchId <= currentCompletePatchId;
		}
	}

    public void stop() {
        stop.set(true);
    }
	
//=============================================================================
//-----------------PRIVATE METHODS---------------------------------------------
	private void initThread() {
		// start thread
		Thread t = new Thread(new Runnable() {			
			@Override
			public void run() {
				while (stop.get() == false) {
                    IGraphAction action = null;
					synchronized(generalMutex) {
						if (!actions.isEmpty()) {
                            action = actions.poll();
						}
					}
					
					if (action == null) {
						try {
							Thread.sleep(100);
						} catch (Exception ex) {}
					} else {
                        applyAction(action);
					}
				}
			}
		});
		t.setDaemon(true);
		t.start();
	}
	
	private void applyAction(IGraphAction action) {
		try {
		    IGraphRenderer graphRenderer = null;
			// lock
			while (graphRenderer == null) {
                graphRenderer = topScreen.lock(action.getProgressTask());
				if (graphRenderer == null) {
					try {
						Thread.sleep(100);
					} catch (Exception ex) {}
				}
			}
			
			// execute
            action.apply(graphRenderer);
			
			// unlock
			topScreen.unlock();
			
			// update tasks
			currentCompletePatchId++;
		} catch (Throwable ex) {
			MainManager.logger.printException(ex);
		}
	}
}
